<%
    KB = 1024
    MB = 1024*1024
    GB = 1024*1024*1024
    start_addr = 0
    def readable_size(value):
        if value > GB:
            return f"{value/GB} GB"
        if value > MB:
            return f"{value/MB} MB"
        if value > KB:
            return f"{value/KB} KB"
        return value

    def not_4k_align(value) -> bool:
        if value & (4096-1):
            return True
        return False

    pci_devices_bundles_cnt = 0
    mem_regions_bundles_cnt = 0
    if ivshmem['isvshmem_bundle']:
        pci_devices_bundles_cnt = 3
        mem_regions_bundles_cnt = 12
%>
/*
 * Jailhouse, a Linux-based partitioning hypervisor
 * Guest cell configuration for ${name}
 * Created by resource-tool
 */

#include <jailhouse/types.h>
#include <jailhouse/cell-config.h>

struct {
    struct jailhouse_cell_desc cell;
    __u64 cpus[${len(cpu["bitmap"])}];
    struct jailhouse_memory mem_regions[${len(system_mem)+len(memmaps)+len(devices)+len(mem_regions)+ivshmem['count']+2 + mem_regions_bundles_cnt +1}];
    count=${ivshmem['count']}
    struct jailhouse_irqchip irqchips[${(gic["gic_int_no_max"] // 128) +1}];
    struct jailhouse_pci_device pci_devices[${1+len(pci_devices["devices"]) + pci_devices_bundles_cnt}];
    %if len(pci_devices["caps"]) > 0:
    struct jailhouse_pci_capability pci_caps[${len(pci_devices["caps"])}];
    %endif
} __attribute__((packed)) config = {
    .cell = {
        .signature = JAILHOUSE_CELL_DESC_SIGNATURE,
        .revision = JAILHOUSE_CONFIG_REVISION,
        %if system['arch'] == 'AArch32':
        .architecture = JAILHOUSE_ARM,
        %else:
        .architecture = JAILHOUSE_ARM64,
        %endif
        .name = "${name}",
        <%
            cell_flags = list()
            cell_flags.append('JAILHOUSE_CELL_PASSIVE_COMMREG')
            if system['arch'] == 'AArch32':
                cell_flags.append('JAILHOUSE_CELL_AARCH32')
            if system['virt_console']:
                cell_flags.append('JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED')
        %>
        .flags = ${'|'.join(cell_flags)},
        .cpu_reset_address = ${hex(system['reset_addr'])},
        %if system['virt_cpuid']:
        .use_virt_cpuid = 1,
        %endif
        .cpu_set_size = sizeof(config.cpus),
        .num_memory_regions = ARRAY_SIZE(config.mem_regions),
        .num_irqchips = ARRAY_SIZE(config.irqchips),
        .num_pci_devices = ARRAY_SIZE(config.pci_devices),
        %if len(pci_devices["caps"]) > 0:
        .num_pci_caps = ARRAY_SIZE(config.pci_caps),
        %endif
        .vpci_irq_base = ${system["vpci_irq_base"]},


        %if console:
        .console = {
            .address = ${hex(console['addr'])},
            .size = ${hex(console['size'])},
            .type = ${console['type'].name}
            .flags = JAILHOUSE_CON_ACCESS_MMIO | JAILHOUSE_CON_REGDIST_4,
        },
        %endif
    },

    .cpus = {
        // CPU: ${cpu['cpus']}
        ${', '.join(cpu['bitmap'])}
    },

    .irqchips = {
        %for idx in range((gic["gic_int_no_max"] // 128) +1):
        {
            .address = ${hex(gic["gicd_base"])},  
            .pin_base = ${idx * 128  + 32 } ,
            .pin_bitmap = {  
                %for bitmap_idx in range(0 + idx*4, 4 + idx*4):
                %if bitmap_idx+1 > len(system['irq_bitmaps'])- 1:
                    0x00000000,   
                %else:
                    ${f"0x{system['irq_bitmaps'][bitmap_idx+1]['bitmap']:08x}"},  // ${system['irq_bitmaps'][bitmap_idx+1]['comment']}
                %endif
                %endfor
            }
        },
        %endfor
    },

    .mem_regions = {
        %if ivshmem:
        /* IVSHMEM regions */
        {
            .phys_start = ${hex(ivshmem['phys'])},
            .virt_start = ${hex(ivshmem['virt'])},
            .size       = ${hex(ivshmem['state_size'])},  // ${readable_size(ivshmem['state_size'] )}
            .flags      = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED,
        },
        {
            .phys_start = ${hex(ivshmem['phys']+ivshmem['state_size'])},
            .virt_start = ${hex(ivshmem['virt']+ivshmem['state_size'])},
            .size       = ${hex(ivshmem['rw_size'])},  // ${readable_size(ivshmem['rw_size'] )} 
            .flags      = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_ROOTSHARED,
        },
        %for idx in range(ivshmem['count']):
        {
            .phys_start = ${hex(ivshmem['phys']+ivshmem['state_size']+ivshmem['rw_size'] + ivshmem['out_size']*idx)},
            .virt_start = ${hex(ivshmem['virt']+ivshmem['state_size']+ivshmem['rw_size'] + ivshmem['out_size']*idx)},
            .size       = ${hex(ivshmem['out_size'])},  // ${readable_size(ivshmem['out_size'])}
            %if idx == ivshmem['id']:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_ROOTSHARED,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED,
            %endif
        },
        %endfor
        <%
            start_addr = ivshmem['phys']+ivshmem['state_size']+ivshmem['rw_size'] + ivshmem['out_size']*idx + ivshmem['out_size']
        %>
        %if ivshmem['isvshmem_bundle']:
        /* IVSHMEM bundle regions (virtio-blk + virtio-console + virtio-net)*/
        /* IVSHMEM shared memory region (virtio-blk front-end) */
        {
            .phys_start = ${hex(start_addr)},
            .virt_start = ${hex(start_addr)},
            .size = 0x1000,   //${readable_size(0x1000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED,
        },
        {
            .phys_start = ${hex(start_addr + 0x1000)},
            .virt_start = ${hex(start_addr + 0x1000)},
            .size = 0xdf000,  //${readable_size(0xdf000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_ROOTSHARED,
        },
        { 0 },
        { 0 },
        <%
            start_addr = start_addr + 0x1000 + 0xdf000
        %>
        /* IVSHMEM shared memory region (virtio-con front-end) */
        {
            .phys_start = ${hex(start_addr)},
            .virt_start = ${hex(start_addr)},
            .size = 0x1000,  //${readable_size(0x1000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED ,
        },
        {
            .phys_start = ${hex(start_addr + 0x1000)},
            .virt_start = ${hex(start_addr + 0x1000)},
            .size = 0xf000,   //${readable_size(0xf000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_ROOTSHARED,
        },
        { 0 },
        { 0 },
        <%
            start_addr = start_addr + 0x1000 + 0xf000
        %>
        /* IVSHMEM shared memory regions for 00:01.0 (networking) */
        {
            .phys_start = ${hex(start_addr)},
            .virt_start = ${hex(start_addr)},  
            .size = 0x1000,  //${readable_size(0x1000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, 
        },
        { 0 },
        <%
            start_addr = start_addr + 0x1000
        %>
        %for idx in range(2):
        {
            .phys_start = ${hex(start_addr )},
            .virt_start = ${hex(start_addr )},
            .size = 0x7f000,  //${readable_size(0x7f000)}
            %if idx == ivshmem['id']:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_ROOTSHARED,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED,
            %endif
            <%
            start_addr = start_addr + 0x7f000
            %>
        },
        %endfor
        %endif 
        %endif

        /****************/
        /* System memory
         ****************/

        %for mem in system_mem:
        %if len(mem['comment']) > 0:
        /* ${mem['comment']} */
        %endif
        {
            .phys_start = ${hex(mem["phys"])},
            .virt_start = ${hex(mem['virt'])},
            .size = ${hex(mem['size'])},  // ${readable_size(mem['size'])}
            %if mem['type'] == 'RESOURCE_TABLE':
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_LOADABLE | JAILHOUSE_MEM_DMA | JAILHOUSE_MEM_RESOURCE_TABLE,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE | JAILHOUSE_MEM_DMA,
            %endif
        },
        %endfor

        /*************/
        /* Memory map (shared from mem_regions)
         *************/
        %for mem in mem_regions:
        %if len(mem['comment']) > 0:
        /* ${mem['comment']} */
        %endif
        {
            .phys_start = ${hex(mem["phys"])},
            .virt_start = ${hex(mem['virt'])},
            .size = ${hex(mem['size'])},  //${readable_size(mem['size'])}
            %if not_4k_align(mem["phys"]) or not_4k_align(mem['size']):
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED | JAILHOUSE_MEM_IO_UNALIGNED,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED,
            %endif
        },
        %endfor
        /*************/
        /* Memory map 
         *************/
        %for mem in memmaps:
        %if len(mem['comment']) > 0:
        /* ${mem['comment']} */
        %endif
        {
            .phys_start = ${hex(mem["phys"])},
            .virt_start = ${hex(mem['virt'])},
            .size = ${hex(mem['size'])},  // ${readable_size(mem['size'])}
            %if not_4k_align(mem["phys"]) or not_4k_align(mem['size']):
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED | JAILHOUSE_MEM_IO_UNALIGNED,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED,
            %endif
        },
        %endfor

        /*************/
        /* device
         *************/

        %for dev in devices:
        /* ${dev['name']} */
        {
            .phys_start = ${hex(dev['addr'])},
            .virt_start = ${hex(dev['addr'])},
            .size       = ${hex(dev['size'])}, //${readable_size(dev['size'])}
            .flags      = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO |JAILHOUSE_MEM_ROOTSHARED,
        },
        %endfor

        /* communication region */
        {
            .virt_start = ${hex(comm_region)},
            .size = 0x00001000,  //${readable_size(0x00001000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_COMM_REGION,
        },
    },

    .pci_devices = {
        %if ivshmem is not None:
        /* ivshmem */
        {
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 1,
            .bdf = 0 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX,
            .shmem_regions_start = 0,
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = ${ivshmem['count']},
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED,
        },
        %if ivshmem['isvshmem_bundle']:
        { /* IVSHMEM (virtio-blk front-end) */
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0,
            .bdf = 0x01 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 2,
            .shmem_regions_start = ${ivshmem['count'] + 2},
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = 2,
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT +
                VIRTIO_DEV_BLOCK,
        },
        { /* IVSHMEM (virtio-con front-end) */
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0,
            .bdf = 0x02 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 3,
            .shmem_regions_start = ${ivshmem['count'] + 2 + 4},
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = 2,
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_FRONT +
                VIRTIO_DEV_CONSOLE,
        },
        { /* IVSHMEM (networking) */
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0000,
            .bdf = 0x03 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 2,
            .shmem_regions_start = ${ivshmem['count'] + 2 + 4 + 4},
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = 2,
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH,
        },
        %endif
        %endif
    },

};